package com.ruoyi.file.service.storage.base;

import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.file.utils.FilePathUtils;
import com.ruoyi.file.utils.FileTypeUtils;
import com.ruoyi.file.utils.S3ClientFactory;
import com.ruoyi.file.domain.SysStorageConfig;
import com.ruoyi.file.domain.vo.UploadTokenVO;
import com.ruoyi.file.enums.StorageTypeEnum;
import com.ruoyi.file.service.storage.StorageService;
import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;
import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.UploadPartPresignRequest;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
import software.amazon.awssdk.services.sts.model.AssumeRoleResponse;
import software.amazon.awssdk.services.sts.model.Credentials;

import java.io.InputStream;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * S3存储服务基础实现
 * 提供通用的S3兼容存储服务功能，子类可以重写特定方法来实现存储类型特有的逻辑
 *
 * @author ruoyi
 */
@Slf4j
public abstract class BaseS3StorageServiceImpl implements StorageService {

    /**
     * 获取存储类型，子类必须实现
     */
    protected abstract StorageTypeEnum getStorageType();

    /**
     * 获取存储类型枚举，如果未知类型则返回null
     */
    protected StorageTypeEnum getStorageType(SysStorageConfig config) {
        try {
            return StorageTypeEnum.getByCode(config.getStorageType());
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    @Override
    public String uploadFile(InputStream inputStream, String fileName, String contentType, SysStorageConfig config) {
        return uploadFile(inputStream, fileName, contentType, config, null);
    }

    @Override
    public String uploadFile(InputStream inputStream, String fileName, String contentType, SysStorageConfig config, String targetPath) {
        try (S3Client s3Client = createS3Client(config)) {
            // 使用 combinePathAndFileName 只拼接路径，不添加时间戳
            String filePath = FilePathUtils.combinePathAndFileName(fileName, targetPath);

            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(config.getBucketName())
                    .key(filePath)
                    .contentType(contentType)
                    .build();

            s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, inputStream.available()));

            return filePath;
        } catch (Exception e) {
            log.error("上传文件失败: {}", e.getMessage(), e);
            throw new ServiceException("上传文件失败: " + e.getMessage());
        }
    }

    @Override
    public InputStream downloadFile(String filePath, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                    .bucket(config.getBucketName())
                    .key(filePath)
                    .build();

            return s3Client.getObject(getObjectRequest);
        } catch (Exception e) {
            log.error("下载文件失败: {}", e.getMessage(), e);
            throw new ServiceException("下载文件失败: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteFile(String filePath, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            DeleteObjectRequest deleteObjectRequest = DeleteObjectRequest.builder()
                    .bucket(config.getBucketName())
                    .key(filePath)
                    .build();

            s3Client.deleteObject(deleteObjectRequest);
            return true;
        } catch (Exception e) {
            log.error("删除文件失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public String getFileUrl(String filePath, SysStorageConfig config) {
        if (StringUtils.isNotBlank(config.getDomain())) {
            // 使用自定义域名
            return config.getDomain().replaceAll("/$", "") + "/" + filePath;
        } else {
            // 使用默认域名
            String protocol = config.getIsHttps() == 1 ? "https" : "http";
            String endpoint = config.getEndpoint().replaceAll("^https?://", "");

            StorageTypeEnum storageType = getStorageType(config);
            return buildFileUrl(protocol, endpoint, config.getBucketName(), filePath, storageType);
        }
    }

    /**
     * 构建文件URL，子类可以重写此方法来实现特定的URL构建逻辑
     */
    protected String buildFileUrl(String protocol, String endpoint, String bucketName, String filePath, StorageTypeEnum storageType) {
        // 创建一个临时的配置对象以便使用S3ClientFactory的方法
        SysStorageConfig tempConfig = new SysStorageConfig();
        tempConfig.setStorageType(storageType.getCode());
        return S3ClientFactory.buildFileUrl(protocol, endpoint, bucketName, filePath, tempConfig);
    }

    @Override
    public String getPresignedUploadUrl(String filePath, SysStorageConfig config, Duration expiration) {
        try (S3Presigner presigner = createS3Presigner(config)) {
            PutObjectRequest.Builder putObjectBuilder = PutObjectRequest.builder()
                    .bucket(config.getBucketName())
                    .key(filePath);

            // 根据存储类型决定是否设置content-type
            if (shouldSetContentType()) {
                putObjectBuilder.contentType("application/octet-stream");
            }

            PutObjectRequest putObjectRequest = putObjectBuilder.build();

            PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
                    .signatureDuration(expiration)
                    .putObjectRequest(putObjectRequest)
                    .build();

            return presigner.presignPutObject(presignRequest).url().toString();
        } catch (Exception e) {
            log.error("生成预签名上传URL失败: {}", e.getMessage(), e);
            throw new ServiceException("生成预签名上传URL失败: " + e.getMessage());
        }
    }

    /**
     * 是否应该设置content-type，子类可以重写
     * 默认返回true，子类可以重写返回false
     */
    protected boolean shouldSetContentType() {
        return true; // 默认设置content-type
    }

    @Override
    public String getPresignedDownloadUrl(String filePath, SysStorageConfig config, Duration expiration) {
        try (S3Presigner presigner = createS3Presigner(config)) {
            GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                    .bucket(config.getBucketName())
                    .key(filePath)
                    .build();

            GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder()
                    .signatureDuration(expiration)
                    .getObjectRequest(getObjectRequest)
                    .build();

            return presigner.presignGetObject(presignRequest).url().toString();
        } catch (Exception e) {
            log.error("生成预签名下载URL失败: {}", e.getMessage(), e);
            throw new ServiceException("生成预签名下载URL失败: " + e.getMessage());
        }
    }

    @Override
    public boolean fileExists(String filePath, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
                    .bucket(config.getBucketName())
                    .key(filePath)
                    .build();

            s3Client.headObject(headObjectRequest);
            return true;
        } catch (NoSuchKeyException e) {
            return false;
        } catch (Exception e) {
            log.error("检查文件是否存在失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public UploadTokenVO generateUploadToken(String fileName, SysStorageConfig config) {
        String filePath = FilePathUtils.generateFilePathWithDate(fileName);
        Duration expiration = Duration.ofSeconds(config.getTokenExpireTime());

        StorageTypeEnum storageType = getStorageType();
        if (storageType == StorageTypeEnum.AWS) {
            // AWS S3 使用 STS 临时凭证
            return generateAwsStsToken(filePath, config, expiration);
        } else {
            // 其他S3兼容存储使用预签名URL
            return generatePresignedToken(filePath, config, expiration);
        }
    }

    @Override
    public UploadTokenVO generateUploadToken(String fileName, SysStorageConfig config, String dirPath) {
        // 使用 combinePathAndFileName 只拼接路径，不添加时间戳
        String filePath = FilePathUtils.combinePathAndFileName(fileName, dirPath);
        Duration expiration = Duration.ofSeconds(config.getTokenExpireTime());

        StorageTypeEnum storageType = getStorageType();
        if (storageType == StorageTypeEnum.AWS) {
            // AWS S3 使用 STS 临时凭证
            return generateAwsStsToken(filePath, config, expiration);
        } else {
            // 其他S3兼容存储使用预签名URL
            return generatePresignedToken(filePath, config, expiration);
        }
    }

    /**
     * 生成AWS STS临时凭证，子类可以重写
     */
    protected UploadTokenVO generateAwsStsToken(String filePath, SysStorageConfig config, Duration expiration) {
        try (StsClient stsClient = createStsClient(config)) {
            // 这里需要配置IAM角色，实际使用时需要替换为真实的角色ARN
            String roleArn = "arn:aws:iam::123456789012:role/S3UploadRole";

            AssumeRoleRequest assumeRoleRequest = AssumeRoleRequest.builder()
                    .roleArn(roleArn)
                    .roleSessionName("file-upload-" + System.currentTimeMillis())
                    .durationSeconds((int) expiration.getSeconds())
                    .build();

            AssumeRoleResponse assumeRoleResult = stsClient.assumeRole(assumeRoleRequest);
            Credentials credentials = assumeRoleResult.credentials();

            return UploadTokenVO.builder()
                    .accessKey(credentials.accessKeyId())
                    .secretKey(credentials.secretAccessKey())
                    .sessionToken(credentials.sessionToken())
                    .endpoint(config.getEndpoint())
                    .bucketName(config.getBucketName())
                    .region(config.getRegion())
                    .filePath(filePath)
                    .expireTime(credentials.expiration().toEpochMilli())
                    .maxFileSize(config.getMaxFileSize())
                    .allowedTypes(parseAllowedTypes(config.getAllowedFileTypes()))
                    .configId(config.getConfigId())
                    .build();
        } catch (Exception e) {
            log.error("生成AWS STS临时凭证失败: {}", e.getMessage(), e);
            throw new ServiceException("生成临时凭证失败: " + e.getMessage());
        }
    }

    /**
     * 生成预签名URL令牌
     */
    protected UploadTokenVO generatePresignedToken(String filePath, SysStorageConfig config, Duration expiration) {
        String uploadUrl = getPresignedUploadUrl(filePath, config, expiration);

        return UploadTokenVO.builder()
                .uploadUrl(uploadUrl)
                .endpoint(config.getEndpoint())
                .bucketName(config.getBucketName())
                .region(config.getRegion())
                .filePath(filePath)
                .expireTime(Instant.now().plus(expiration).toEpochMilli())
                .maxFileSize(config.getMaxFileSize())
                .allowedTypes(parseAllowedTypes(config.getAllowedFileTypes()))
                .configId(config.getConfigId())
                .build();
    }

    /**
     * 创建S3客户端
     */
    protected S3Client createS3Client(SysStorageConfig config) {
        return S3ClientFactory.createS3Client(config, this);
    }

    /**
     * 是否使用路径风格，子类可以重写
     * 默认返回false（虚拟主机风格），子类可以重写返回true（路径风格）
     */
    public boolean shouldUsePathStyle() {
        return false; // 默认使用虚拟主机风格
    }

    /**
     * 创建S3预签名器
     */
    protected S3Presigner createS3Presigner(SysStorageConfig config) {
        return S3ClientFactory.createS3Presigner(config, this);
    }


    /**
     * 创建STS客户端
     */
    protected StsClient createStsClient(SysStorageConfig config) {
        return S3ClientFactory.createStsClient(config);
    }

    @Override
    public boolean createBucket(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            CreateBucketRequest createBucketRequest = CreateBucketRequest.builder()
                    .bucket(bucketName)
                    .build();
            s3Client.createBucket(createBucketRequest);
            return true;
        } catch (BucketAlreadyExistsException e) {
            log.error("创建存储桶失败，桶名已存在: {}", bucketName);
            throw new ServiceException("桶名称 '" + bucketName + "' 已被使用，请选择其他名称");
        } catch (Exception e) {
            log.error("创建存储桶失败: {}", e.getMessage(), e);
            throw new ServiceException("创建存储桶失败: " + e.getMessage());
        }
    }

    @Override
    public boolean deleteBucket(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            // 先清空存储桶中的所有对象
            if (!clearBucketObjects(s3Client, bucketName)) {
                log.error("清空存储桶失败: {}", bucketName);
                return false;
            }
            
            // 删除存储桶
            DeleteBucketRequest deleteBucketRequest = DeleteBucketRequest.builder()
                    .bucket(bucketName)
                    .build();
            s3Client.deleteBucket(deleteBucketRequest);
            log.info("删除存储桶成功: {}", bucketName);
            return true;
        } catch (Exception e) {
            log.error("删除存储桶失败: bucketName={}, error={}", bucketName, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 清空存储桶中的所有对象
     * @param s3Client S3客户端
     * @param bucketName 存储桶名称
     * @return 是否清空成功
     */
    private boolean clearBucketObjects(S3Client s3Client, String bucketName) {
        try {
            // 分批删除对象，避免一次性删除过多对象导致超时
            String continuationToken = null;
            int totalDeleted = 0;
            
            do {
                // 列出对象
                ListObjectsV2Request.Builder listRequestBuilder = ListObjectsV2Request.builder()
                        .bucket(bucketName)
                        .maxKeys(1000); // 每批最多处理1000个对象
                
                if (continuationToken != null) {
                    listRequestBuilder.continuationToken(continuationToken);
                }
                
                ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequestBuilder.build());
                
                if (listResponse.contents().isEmpty()) {
                    break; // 没有更多对象了
                }
                
                // 批量删除对象
                List<ObjectIdentifier> objectsToDelete = listResponse.contents().stream()
                        .map(s3Object -> ObjectIdentifier.builder()
                                .key(s3Object.key())
                                .build())
                        .collect(Collectors.toList());
                
                Delete delete = Delete.builder()
                        .objects(objectsToDelete)
                        .quiet(true) // 静默模式，不返回删除成功的对象列表
                        .build();
                
                DeleteObjectsRequest deleteRequest = DeleteObjectsRequest.builder()
                        .bucket(bucketName)
                        .delete(delete)
                        .build();
                
                DeleteObjectsResponse deleteResponse = s3Client.deleteObjects(deleteRequest);
                
                // 检查是否有删除失败的对象
                if (deleteResponse.hasErrors()) {
                    for (software.amazon.awssdk.services.s3.model.S3Error error : deleteResponse.errors()) {
                        log.warn("删除对象失败: key={}, code={}, message={}", 
                                error.key(), error.code(), error.message());
                    }
                }
                
                int deletedCount = objectsToDelete.size() - (deleteResponse.hasErrors() ? deleteResponse.errors().size() : 0);
                totalDeleted += deletedCount;
                
                log.debug("批量删除对象: bucket={}, count={}, total={}", bucketName, deletedCount, totalDeleted);
                
                // 获取下一批的继续令牌
                continuationToken = listResponse.isTruncated() ? listResponse.nextContinuationToken() : null;
                
            } while (continuationToken != null);
            
            log.info("清空存储桶完成: bucket={}, totalDeleted={}", bucketName, totalDeleted);
            return true;
            
        } catch (Exception e) {
            log.error("清空存储桶对象失败: bucket={}, error={}", bucketName, e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean bucketExists(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            HeadBucketRequest headBucketRequest = HeadBucketRequest.builder()
                    .bucket(bucketName)
                    .build();
            s3Client.headBucket(headBucketRequest);
            return true;
        } catch (Exception e) {
            log.debug("存储桶不存在或无权限访问: {}", bucketName);
            return false;
        }
    }

    @Override
    public List<String> listBuckets(SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            ListBucketsResponse response = s3Client.listBuckets();
            return response.buckets().stream()
                    .map(Bucket::name)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("获取存储桶列表失败: {}", e.getMessage(), e);
            return new java.util.ArrayList<>();
        }
    }

    @Override
    public boolean setBucketPermission(String bucketName, String permission, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            BucketCannedACL acl = switch (permission.toLowerCase()) {
                case "private" -> BucketCannedACL.PRIVATE;
                case "public-read" -> BucketCannedACL.PUBLIC_READ;
                case "public-read-write" -> BucketCannedACL.PUBLIC_READ_WRITE;
                default -> {
                    log.error("不支持的权限类型: {}", permission);
                    throw new ServiceException("不支持的权限类型: " + permission);
                }
            };
            PutBucketAclRequest putBucketAclRequest = PutBucketAclRequest.builder()
                    .bucket(bucketName)
                    .acl(acl)
                    .build();
            s3Client.putBucketAcl(putBucketAclRequest);
            return true;
        } catch (Exception e) {
            log.error("设置存储桶权限失败: {}", e.getMessage(), e);
            throw new ServiceException("设置存储桶权限失败: " + e.getMessage());
        }
    }

    @Override
    public String getBucketPermission(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            GetBucketAclRequest getBucketAclRequest = GetBucketAclRequest.builder()
                    .bucket(bucketName)
                    .build();
            GetBucketAclResponse response = s3Client.getBucketAcl(getBucketAclRequest);
            // 简化权限判断逻辑
            boolean hasPublicRead = response.grants().stream()
                    .anyMatch(grant -> grant.grantee() != null
                            && grant.grantee().uri() != null
                            && grant.grantee().uri().contains("AllUsers")
                            && grant.permission() == Permission.READ);
            boolean hasPublicWrite = response.grants().stream()
                    .anyMatch(grant -> grant.grantee() != null
                            && grant.grantee().uri() != null
                            && grant.grantee().uri().contains("AllUsers")
                            && (grant.permission() == Permission.WRITE || grant.permission() == Permission.WRITE_ACP));
            if (hasPublicRead && hasPublicWrite) {
                return "public-read-write";
            } else if (hasPublicRead) {
                return "public-read";
            } else {
                return "private";
            }
        } catch (Exception e) {
            log.error("获取存储桶权限失败: {}", e.getMessage(), e);
            return "unknown";
        }
    }

    /**
     * 解析允许的文件类型
     */
    protected List<String> parseAllowedTypes(String allowedFileTypes) {
        return FileTypeUtils.parseAllowedTypes(allowedFileTypes);
    }

    // ==================== S3原生分片上传实现 ====================

    @Override
    public String initMultipartUpload(String fileName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            String bucketName = config.getBucketName();
            
            CreateMultipartUploadRequest request = CreateMultipartUploadRequest.builder()
                    .bucket(bucketName)
                    .key(fileName)
                    .build();
                    
            CreateMultipartUploadResponse response = s3Client.createMultipartUpload(request);
            String uploadId = response.uploadId();
            
            return uploadId;
        } catch (Exception e) {
            log.error("初始化分片上传失败: {}", e.getMessage(), e);
            throw new ServiceException("初始化分片上传失败: " + e.getMessage());
        }
    }

    @Override
    public String getPresignedUploadUrl(String fileName, String uploadId, int partNumber, SysStorageConfig config) {
        try (S3Presigner presigner = createS3Presigner(config)) {
            String bucketName = config.getBucketName();
            
            UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                    .bucket(bucketName)
                    .key(fileName)
                    .uploadId(uploadId)
                    .partNumber(partNumber)
                    .build();
                    
            UploadPartPresignRequest presignRequest = UploadPartPresignRequest.builder()
                    .signatureDuration(Duration.ofHours(1)) // 1小时有效期
                    .uploadPartRequest(uploadPartRequest)
                    .build();
                    
            String presignedUrl = presigner.presignUploadPart(presignRequest).url().toString();
            
            return presignedUrl;
        } catch (Exception e) {
            log.error("生成分片预签名URL失败: {}", e.getMessage(), e);
            throw new ServiceException("生成分片预签名URL失败: " + e.getMessage());
        }
    }

    @Override
    public String uploadPart(String fileName, String uploadId, int partNumber, InputStream inputStream, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            String bucketName = config.getBucketName();
            
            // 创建分片上传请求
            UploadPartRequest uploadPartRequest = UploadPartRequest.builder()
                    .bucket(bucketName)
                    .key(fileName)
                    .uploadId(uploadId)
                    .partNumber(partNumber)
                    .build();
            
            // 上传分片
            UploadPartResponse response = s3Client.uploadPart(uploadPartRequest, 
                    RequestBody.fromInputStream(inputStream, inputStream.available()));
            
            String etag = response.eTag();
            
            return etag;
        } catch (Exception e) {
            log.error("分片上传失败: bucket={}, key={}, uploadId={}, partNumber={}, error={}", 
                     config.getBucketName(), fileName, uploadId, partNumber, e.getMessage(), e);
            throw new ServiceException("分片上传失败: " + e.getMessage());
        }
    }

    @Override
    public boolean completeMultipartUpload(String fileName, String uploadId, 
            java.util.List<com.ruoyi.file.domain.dto.CompleteMultipartRequest.PartInfo> parts, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            String bucketName = config.getBucketName();
            
            // 转换分片信息
            List<CompletedPart> completedParts = parts.stream()
                    .map(part -> CompletedPart.builder()
                            .partNumber(part.getPartNumber())
                            .eTag(part.getEtag())
                            .build())
                    .collect(Collectors.toList());
                    
            CompletedMultipartUpload completedMultipartUpload = CompletedMultipartUpload.builder()
                    .parts(completedParts)
                    .build();
                    
            CompleteMultipartUploadRequest request = CompleteMultipartUploadRequest.builder()
                    .bucket(bucketName)
                    .key(fileName)
                    .uploadId(uploadId)
                    .multipartUpload(completedMultipartUpload)
                    .build();
                    
            CompleteMultipartUploadResponse response = s3Client.completeMultipartUpload(request);
            
            return true;
        } catch (Exception e) {
            log.error("完成分片上传失败: {}", e.getMessage(), e);
            throw new ServiceException("完成分片上传失败: " + e.getMessage());
        }
    }

    @Override
    public boolean abortMultipartUpload(String fileName, String uploadId, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            String bucketName = config.getBucketName();
            
            AbortMultipartUploadRequest request = AbortMultipartUploadRequest.builder()
                    .bucket(bucketName)
                    .key(fileName)
                    .uploadId(uploadId)
                    .build();
                    
            s3Client.abortMultipartUpload(request);
            
            return true;
        } catch (Exception e) {
            log.error("取消分片上传失败: {}", e.getMessage(), e);
            throw new ServiceException("取消分片上传失败: " + e.getMessage());
        }
    }

    // ==================== CORS配置实现 ====================

    @Override
    public boolean configureBucketCors(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            // 创建CORS规则 - 允许前端直传
            CORSRule corsRule = CORSRule.builder()
                    .allowedHeaders("*")
                    .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD")
                    .allowedOrigins("*") // 生产环境建议限制具体域名
                    .maxAgeSeconds(3600)
                    .exposeHeaders("ETag", "x-amz-request-id")
                    .build();

            CORSConfiguration corsConfiguration = CORSConfiguration.builder()
                    .corsRules(java.util.Collections.singletonList(corsRule))
                    .build();

            PutBucketCorsRequest corsRequest = PutBucketCorsRequest.builder()
                    .bucket(bucketName)
                    .corsConfiguration(corsConfiguration)
                    .build();

            s3Client.putBucketCors(corsRequest);
            
            return true;
        } catch (Exception e) {
            log.error("配置存储桶CORS失败: {}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public String getBucketCors(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            GetBucketCorsRequest corsRequest = GetBucketCorsRequest.builder()
                    .bucket(bucketName)
                    .build();

            GetBucketCorsResponse response = s3Client.getBucketCors(corsRequest);
            
            if (response.corsRules() != null && !response.corsRules().isEmpty()) {
                CORSRule rule = response.corsRules().get(0);
                // 将枚举转换为字符串
                java.util.List<String> methods = rule.allowedMethods().stream()
                    .map(Object::toString)
                    .collect(java.util.stream.Collectors.toList());
                return String.format("CORS已配置 - 允许方法: %s, 允许来源: %s", 
                    String.join(",", methods), 
                    String.join(",", rule.allowedOrigins()));
            }
            
            return "未配置CORS";
        } catch (Exception e) {
            log.warn("获取存储桶CORS配置失败: {}", e.getMessage());
            return "获取CORS配置失败: " + e.getMessage();
        }
    }

    @Override
    public boolean deleteBucketCors(String bucketName, SysStorageConfig config) {
        try (S3Client s3Client = createS3Client(config)) {
            DeleteBucketCorsRequest corsRequest = DeleteBucketCorsRequest.builder()
                    .bucket(bucketName)
                    .build();

            s3Client.deleteBucketCors(corsRequest);
            
            return true;
        } catch (Exception e) {
            log.error("删除存储桶CORS配置失败: {}", e.getMessage(), e);
            return false;
        }
    }

}
